#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
#include <gmp.h>
#include <pthread.h>
#define NTHREADS 4

pthread_t vector_thread[NTHREADS];

unsigned long int iteration_number = 99493984;
unsigned long int points_count = 0;

pthread_mutex_t mutex;

mpf_t PI;
mpf_t cont_points;
mpf_t total;

void *point_counter(void *n){

    int i, m = (int *)n;
    double x, y;
    double value;

    for(i=m; i<iteration_number; i+=NTHREADS ){
        x = drand48();
        y = drand48();

        value = ((x*x) + (y*y));

        if(value <= 1){
            pthread_mutex_lock( &mutex);
            points_count++;
            pthread_mutex_unlock( &mutex);
        }
    }



    pthread_exit((void *) n);
}

int main(){
    int i;
    int flag;
    void *n;
    time_t start, end;
    start = time(NULL);

    pthread_mutex_init( &mutex, NULL);

    mpf_set_default_prec(40000016);

    mpf_init_set_ui(PI, 0L);
    mpf_init_set_ui(cont_points, 0L);
    mpf_init_set_ui(total, 0L);

    for(i=0; i<NTHREADS; i++){
        flag = pthread_create(&vector_thread[i], NULL, point_counter, (void*) i);

        if(flag){
            printf("ERROR\n");
            exit(1);
        }
    }

    for(i=0; i<NTHREADS; i++){
        flag = pthread_join(vector_thread[i], &n);

        if(flag){
            printf("ERROR\n");
            exit(1);
        }

    }


    mpf_set_si(cont_points, points_count); //
    mpf_set_si(total, iteration_number);
    mpf_mul_ui(PI, cont_points, 4L); // PI = cont_points * 4
    mpf_div(PI, PI, total); //PI = (cont_points * 4)/total

    mpf_out_str(stdout, 10, 40000016, PI);

    //end = time(NULL);
    //gmp_printf("PI: %.30Ff\n", PI);
    //printf("Execution Time: %.2fs\n", difftime(end,start));

    return 0;
}
